package com.kexilo.system.security.service;

import com.kexilo.core.common.constant.Constants;
import com.kexilo.core.common.utils.IpUtils;
import com.kexilo.core.common.utils.MessageUtils;
import com.kexilo.core.common.utils.ServletUtils;
import com.kexilo.core.common.utils.StringUtils;
import com.kexilo.core.common.utils.MD5Utils;
import com.kexilo.core.security.domain.SysLogininfor;
import com.kexilo.system.security.mapper.SysLogininforMapper;
import eu.bitwalker.useragentutils.UserAgent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 系统访问日志情况信息 服务层处理
 * 
 * @author Kexilo
 */
@Service
public class SysLogininforServiceImpl implements ISysLogininforService {
    
    private static final Logger log = LoggerFactory.getLogger(SysLogininforServiceImpl.class);
    
    @Autowired
    private SysLogininforMapper logininforMapper;

    /**
     * 新增系统登录日志
     * 
     * @param logininfor 访问日志对象
     */
    @Override
    @Async("taskExecutor")
    public void insertLogininfor(SysLogininfor logininfor) {
        try {
            logininforMapper.insertLogininfor(logininfor);
        } catch (Exception e) {
            log.error("保存登录日志异常：{}", e.getMessage(), e);
        }
    }

    /**
     * 查询系统登录日志集合
     * 
     * @param logininfor 访问日志对象
     * @return 登录记录集合
     */
    @Override
    public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor) {
        return logininforMapper.selectLogininforList(logininfor);
    }

    /**
     * 批量删除系统登录日志
     * 
     * @param infoIds 需要删除的登录日志ID
     * @return 结果
     */
    @Override
    public int deleteLogininforByIds(Long[] infoIds) {
        return logininforMapper.deleteLogininforByIds(infoIds);
    }

    /**
     * 清空系统登录日志
     */
    @Override
    public void cleanLogininfor() {
        logininforMapper.cleanLogininfor();
    }

    /**
     * 记录登录信息
     * 
     * @param username 用户名
     * @param status 状态
     * @param message 消息内容
     * @param args 列表
     */
    @Override
    @Async("taskExecutor")
    public void recordLogininfor(final String username, final String status, final String message, final Object... args) {
        final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
        final String ip = IpUtils.getIpAddr();
        
        SysLogininfor logininfor = new SysLogininfor();
        logininfor.setUserName(username);
        logininfor.setIpaddr(ip);
        logininfor.setLoginLocation(IpUtils.getRealAddressByIP(ip));
        logininfor.setBrowser(userAgent.getBrowser().getName());
        logininfor.setOs(userAgent.getOperatingSystem().getName());
        logininfor.setMsg(MessageUtils.message(message, args));
        logininfor.setLoginTime(LocalDateTime.now());
        logininfor.setStatus(status);
        logininfor.setUserAgent(ServletUtils.getRequest().getHeader("User-Agent"));
        logininfor.setTraceId(MDC.get("traceId"));
        
        // 计算设备类型
        if (userAgent.getOperatingSystem().isMobileDevice()) {
            logininfor.setDeviceType("mobile");
        } else {
            logininfor.setDeviceType("desktop");
        }
        
        // 生成设备指纹（简化版）
        String deviceFingerprint = generateDeviceFingerprint(ip, userAgent.toString());
        logininfor.setDeviceFingerprint(deviceFingerprint);
        
        // 计算风险评分
        int riskScore = calculateRiskScore(username, ip, deviceFingerprint);
        logininfor.setRiskScore(riskScore);
        
        // 检查异地登录
        boolean remoteLogin = checkRemoteLogin(username, ip);
        logininfor.setRemoteLogin(remoteLogin);
        
        // 检查新设备登录
        boolean newDevice = checkNewDevice(username, deviceFingerprint);
        logininfor.setNewDevice(newDevice);
        
        // 登录类型
        logininfor.setLoginType("1"); // 默认用户名密码登录
        
        // 认证因子
        logininfor.setAuthFactor("single"); // 默认单因子认证
        
        insertLogininfor(logininfor);
    }

    /**
     * 查询用户最近登录记录
     * 
     * @param userName 用户名
     * @param limit 限制条数
     * @return 登录记录
     */
    @Override
    public List<SysLogininfor> selectRecentLoginByUserName(String userName, int limit) {
        return logininforMapper.selectRecentLoginByUserName(userName, limit);
    }

    /**
     * 计算用户风险评分
     * 
     * @param userName 用户名
     * @param ipaddr IP地址
     * @param deviceFingerprint 设备指纹
     * @return 风险评分
     */
    @Override
    public int calculateRiskScore(String userName, String ipaddr, String deviceFingerprint) {
        int score = 0;
        
        try {
            // 检查失败登录次数（近24小时）
            int failureCount = logininforMapper.selectFailureCountByUserName(userName, 24);
            score += failureCount * 10; // 每次失败登录增加10分
            
            // 检查异地登录（近72小时）
            int remoteLoginCount = logininforMapper.selectRemoteLoginCount(userName, ipaddr, 72);
            if (remoteLoginCount == 0) {
                score += 20; // 异地登录增加20分
            }
            
            // 检查新设备登录
            int deviceLoginCount = logininforMapper.selectLoginCountByDevice(deviceFingerprint, userName);
            if (deviceLoginCount == 0) {
                score += 15; // 新设备登录增加15分
            }
            
            // 当前时间风险（夜间登录）
            int hour = LocalDateTime.now().getHour();
            if (hour < 6 || hour > 22) {
                score += 5; // 夜间登录增加5分
            }
            
        } catch (Exception e) {
            log.error("计算风险评分异常：{}", e.getMessage(), e);
        }
        
        return Math.min(score, 100); // 最高100分
    }

    /**
     * 检查是否异地登录
     * 
     * @param userName 用户名
     * @param ipaddr IP地址
     * @return 是否异地登录
     */
    @Override
    public boolean checkRemoteLogin(String userName, String ipaddr) {
        try {
            // 查询用户近72小时的登录记录
            int count = logininforMapper.selectRemoteLoginCount(userName, ipaddr, 72);
            return count == 0;
        } catch (Exception e) {
            log.error("检查异地登录异常：{}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 检查是否新设备登录
     * 
     * @param userName 用户名
     * @param deviceFingerprint 设备指纹
     * @return 是否新设备登录
     */
    @Override
    public boolean checkNewDevice(String userName, String deviceFingerprint) {
        try {
            int count = logininforMapper.selectLoginCountByDevice(deviceFingerprint, userName);
            return count == 0;
        } catch (Exception e) {
            log.error("检查新设备登录异常：{}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 生成设备指纹
     * 
     * @param ip IP地址
     * @param userAgent 用户代理
     * @return 设备指纹
     */
    private String generateDeviceFingerprint(String ip, String userAgent) {
        // 简化的设备指纹生成，实际应用中可以更复杂
        String raw = ip + "|" + userAgent;
        return MD5Utils.md5(raw);
    }
}
